package com.chenfan.mcn.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.mcn.clients.baseinfo.BaseCustomer;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.baseinfo.DescByCodeDTO;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SUser;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.McnConstant;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.constant.SeparatorCst;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.event.EventPublisher;
import com.chenfan.mcn.event.OperateLogEvent;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.common.extension.dict.DictStream;
import com.chenfan.common.extension.dict.DictTranslationUtils;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.model.dto.*;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.service.BrandInfoService;
import com.chenfan.mcn.utils.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.chenfan.mcn.service.LiveCommodityService;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 直播商品服务实现
 *
 * @author wulg
 * @date 2023/3/13
 */
@SuppressWarnings("AlibabaMethodTooLong")
@Slf4j
@Service
public class LiveCommodityServiceImpl implements LiveCommodityService {

    @Autowired
    private LiveContractCommodityMapper liveContractCommodityMapper;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private LiveStarSettlementDetailMapper liveStarSettlementDetailMapper;

    @Autowired
    private LiveStarSettlementMapper liveStarSettlementMapper;

    @Autowired
    private LiveSessionMapper liveSessionMapper;

    @Autowired
    private StarPlatformInfoMapper starPlatformInfoMapper;

    @Autowired
    private LiveSettlementCommodityMapper liveSettlementCommodityMapper;

    @Autowired
    private BrandInfoService brandInfoService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long save(LiveCommodityInfoSaveDTO saveDTO) {
        boolean exists = liveContractCommodityMapper.exist(Wrappers.lambdaQuery(LiveContractCommodity.class)
                .eq(LiveContractCommodity::getCommodityId, saveDTO.getCommodityId())
                .ne(Objects.nonNull(saveDTO.getId()), LiveContractCommodity::getId, saveDTO.getId()));
        if (exists) {
            String liveDateStr = DateFormatUtils.format(saveDTO.getLiveDate(), McnConstant.SHORT_DATE_FORMAT);
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), String.format("该直播日期【%s】和主播下商品ID已存在", liveDateStr));
        }
        LiveContractCommodity liveContractCommodity = new LiveContractCommodity();
        BeanUtils.copyProperties(saveDTO, liveContractCommodity);
        if (Objects.isNull(liveContractCommodity.getId())) {
            liveContractCommodity.setClaimStatus(NumberCst.ZERO);
            liveContractCommodity.setSettlementStatus(NumberCst.ZERO);
            liveContractCommodity.setCustomerId(this.getCustomerId(StringUtils.trim(saveDTO.getCustomerName())));
            liveContractCommodityMapper.insert(liveContractCommodity);
        } else {
            LiveContractCommodity entity = liveContractCommodityMapper.selectById(liveContractCommodity.getId());
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "无此直播商品");
            BusinessAssert.isTrue(NumberCst.ZERO.equals(entity.getSettlementStatus()), McnErrorCode.BUSINESS_ERROR, "非待结算的商品，不允许修改");
            if (NumberCst.ONE.equals(entity.getClaimStatus()) && !entity.getCommodityId().equals(saveDTO.getCommodityId())) {
                throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "商品已被认领，ID不允许修改！");
            }
            liveContractCommodity.setCustomerId(this.getCustomerId(StringUtils.trim(saveDTO.getCustomerName())));
            liveContractCommodityMapper.updateById(liveContractCommodity);
            EventPublisher.post(OperateLogEvent.builder().businessId(liveContractCommodity.getId())
                    .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                    .compare(entity, liveContractCommodityMapper.selectById(liveContractCommodity.getId()))
                    .build());
        }
        return liveContractCommodity.getId();
    }

    @Override
    public Boolean changeCommodityStatus(LiveCommodityStatusDTO dto) {
        List<LiveContractCommodity> dataList = liveContractCommodityMapper.selectBatchIds(dto.getIdList());
        if (CollectionUtils.isNotEmpty(dataList)) {
            liveContractCommodityMapper.updateByNoStrategy(Wrappers.lambdaUpdate(LiveContractCommodity.class)
                    .in(LiveContractCommodity::getId, dto.getIdList())
                    .set(LiveContractCommodity::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(LiveContractCommodity::getUpdateName, UserVoContextHolder.getUserName())
                    .set(LiveContractCommodity::getUpdateDate, new Date())
            );
            Map<Long, LiveContractCommodity> dataMap = CommonUtil.defaultList(liveContractCommodityMapper.selectBatchIds(dto.getIdList())).stream().collect(Collectors.toMap(k -> k.getId(), Function.identity()));
            dataList.forEach(data -> {
                EventPublisher.post(OperateLogEvent.builder().businessId(data.getId())
                        .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                        .compare(data, dataMap.get(data.getId()))
                        .build());
            });
        }
        return Boolean.TRUE;
    }

    @Override
    public Page<LiveCommodityListVO> page(LiveCommoditySearchDTO searchDTO) {
        searchDTO.setAlias("lcc.");
        Page<LiveCommodityListVO> pageResponse = liveContractCommodityMapper.selectLiveCommoditysWithPayMonthByPage(new Page<>(searchDTO.getPageNum(), searchDTO.getPageSize()), searchDTO);
        // if (StringUtils.isNotBlank(searchDTO.getPayMonth())) {
        //     pageResponse = liveContractCommodityMapper.selectLiveCommoditysWithPayMonthByPage(new Page<>(searchDTO.getPageNum(), searchDTO.getPageSize()),
        //             searchDTO);
        // } else {
        //     pageResponse = liveContractCommodityMapper.selectLiveCommoditysByPage(new Page<>(searchDTO.getPageNum(), searchDTO.getPageSize()),
        //             searchDTO);
        // }
        if (CollectionUtils.isEmpty(pageResponse.getRecords())) {
            return pageResponse;
        }

        List<Long> starPlatIds = pageResponse.getRecords().stream().map(x -> x.getStarPlatId()).collect(Collectors.toList());
        Map<Long, StarPlatInfoVO> anchorMap = CommonUtil.defaultList(starPlatformInfoMapper.getByIds(starPlatIds)).stream().collect(Collectors.toMap(k -> k.getId(), m -> m, (m, n) -> m));
        List<Long> franchiserIds = pageResponse.getRecords().stream().map(LiveContractCommodity::getFranchiserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Long, String> franchiserMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(franchiserIds), () ->
                        CommonUtil.defaultList(privilegeClient.getUserByIds(franchiserIds).getObj()).stream().collect(Collectors.toMap(k -> k.getUserId(), v -> v.getUsername()))
                , Collections.EMPTY_MAP);
        List<String> brandCodes = pageResponse.getRecords().stream().map(LiveCommodityListVO::getCooperateBrand).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
        pageResponse.getRecords().stream().forEach(vo -> {
            if (Objects.nonNull(vo.getFranchiserId())) {
                vo.setFranchiserName(franchiserMap.get(vo.getFranchiserId()));
            }
            StarPlatInfoVO starPlatInfoVO = anchorMap.get(vo.getStarPlatId());
            if (Objects.nonNull(starPlatInfoVO)) {
                vo.setAnchorName(starPlatInfoVO.getPlatNickName());
                vo.setLivePlatformName(starPlatInfoVO.getPlatformName());
            }
            if(brandMap.containsKey(vo.getCooperateBrand())) {
                vo.setCooperateBrandName(brandMap.get(vo.getCooperateBrand()));
            }
        });
        DictTranslationUtils.translation(() -> DictStream.of(
                DictStream.map("liveContractCategory", LiveCommodityListVO::getLiveContractCategory, LiveCommodityListVO::setLiveContractCategoryName)
                ),
                (dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                        .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                pageResponse.getRecords()
        );
        return pageResponse;
    }

    @Override
    public LiveCommodityListVO detail(Long id) {
        LiveContractCommodity entity = liveContractCommodityMapper.selectById(id);
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "无此直播商品");
        LiveCommodityListVO detailVO = new LiveCommodityListVO();
        BeanUtils.copyProperties(entity, detailVO);
        detailVO.setTransactedPrice(entity.getLivePrice());
        DictTranslationUtils.translation(() -> DictStream.of(
                DictStream.map("liveContractCategory", LiveCommodityListVO::getLiveContractCategory, LiveCommodityListVO::setLiveContractCategoryName)
                ),(dictProfileList, dictList) -> baseInfoClient.getDescByCode(new DescByCodeDTO().setDictsCodes(dictList).setProfileCodes(dictProfileList)).getObj(),
                detailVO
        );
        detailVO.setCooperateBrandName(brandInfoService.getBrandNameByCode(detailVO.getCooperateBrand()));
        if (Objects.nonNull(entity.getLsId())) {
            LiveSession liveSession = liveSessionMapper.selectById(entity.getLsId());
            StarPlatformInfo starPlatformInfo = starPlatformInfoMapper.selectById(liveSession.getStarPlatId());
            detailVO.setLivePlatformName(starPlatformInfo.getPlatformName());
            detailVO.setLiveDate(liveSession.getLiveDate());
            detailVO.setAnchorName(starPlatformInfo.getPlatNickName());
        }
        if (Objects.nonNull(entity.getFranchiserId())) {
            SUser sUser = privilegeClient.getUserById(entity.getFranchiserId()).getObj();
            if (Objects.nonNull(sUser)) {
                detailVO.setFranchiserName(sUser.getUsername());
            }
        }
        if (Objects.nonNull(entity.getCustomerId())) {
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(Arrays.asList(entity.getCustomerId())).getObj();
            BaseCustomer baseCustomer = CommonUtil.getMapValue(customerMap, entity.getCustomerId());
            detailVO.setCustomerName(Objects.nonNull(baseCustomer) ? baseCustomer.getCustomerNameC() : null);
        }

        //查询结算商品列表
        List<LiveSettlementCommodityDataVo> dataVos = liveSettlementCommodityMapper.getDetailByLccId(id);
        if (CollUtil.isNotEmpty(dataVos)) {
            detailVO.setShopName(dataVos.get(0).getShopName());
        }
        detailVO.setDataVos(dataVos);
        return detailVO;
    }

    @Override
    public Map<String, Object> exportExcel(LiveCommoditySearchDTO searchDTO) {
        searchDTO.setPageNum(1);
        searchDTO.setPageSize(Integer.MAX_VALUE);
        List<LiveCommodityListVO> dataList = page(searchDTO).getRecords();

        //查询直播标题
        LiveSession liveSession = liveSessionMapper.selectById(searchDTO.getLsId());
        Map<String, Object> result = new HashMap(4);
        result.put("dataList", dataList);
        result.put("live_date", Optional.ofNullable(liveSession).map(x -> cn.hutool.core.date.DateUtil.format(x.getLiveDate(), "yyyy-MM-dd")).orElse(null));
        result.put("title", Optional.ofNullable(liveSession).map(x -> x.getLiveTitle()).orElse(Strings.EMPTY));
        return result;
    }

    @Override
    public void downloadFailedReason(HttpServletResponse response, String fileId, Integer type) {
        BusinessAssert.isTrue(ImportExcelEnum.match(fileId, ImportExcelEnum.LIVE_COMMODITY), McnErrorCode.EXPORT_FILE_ID_ILLEGAL);
        // 根据FileId判断导出类型
        String excelContent = CommonUtil.defaultIfEmpty(stringRedisTemplate.opsForValue().get(McnConstant.CACHE_PRIFIX + fileId));
        List outputList;
        Class c;
        if (type == null) {
            outputList = JSONObject.parseObject(excelContent, new TypeReference<List<LiveCommodityOutputDTO>>() {
            });
            c = LiveCommodityOutputDTO.class;
        } else if (NumberCst.ONE.equals(type)) {
            outputList = JSONObject.parseObject(excelContent, new TypeReference<List<CommodityOutputDTO>>() {
            });
            log.info("type为1时下载内容:{},转换后数据:{}",excelContent, JSON.toJSONString(outputList));
            c = CommodityOutputDTO.class;
        } else if (NumberCst.TWO.equals(type)) {
            outputList = JSONObject.parseObject(excelContent, new TypeReference<List<SettlementCommodityOutputDTO>>() {
            });
            c = SettlementCommodityOutputDTO.class;
        } else {
            throw new BusinessException(500, "类型传参错误");
        }

        BusinessAssert.notEmpty(outputList, McnErrorCode.EXPORT_HAS_NO_DATA);
        try {
            String title = "批量导入直播商品失败原因";
            ExcelUtils.exportExcel(outputList, title, c, title + ".xlsx", response);
            stringRedisTemplate.delete(McnConstant.CACHE_PRIFIX + fileId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public Boolean claim(LiveCommodityClaimDTO dto) {
        IncomeContract incomeContract = null;
        if (Objects.nonNull(dto.getLiveContractId())) {
            incomeContract = incomeContractMapper.selectById(dto.getLiveContractId());
            BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
            BusinessAssert.isTrue(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()), McnErrorCode.BUSINESS_ERROR, "非直播合同，不允许认领");
            BusinessAssert.isFalse(ApprovalStatusEnum.isInvalid(incomeContract.getApprovalStatus()), McnErrorCode.BUSINESS_ERROR, "直播合同已作废，不允许认领");
        } else {
            Assert.hasText(dto.getCustomerName(), "请录入客户名称");
            Assert.hasText(dto.getCooperateBrand(), "请选择品牌");
            Assert.hasText(dto.getLiveContractCategory(), "请选择类目");
            Assert.notNull(dto.getFranchiserId(), "请选择招商");
        }
        List<LiveContractCommodity> dataList = liveContractCommodityMapper.selectBatchIds(dto.getIdList());
        BusinessAssert.notEmpty(dataList, McnErrorCode.DATA_NOT_FOUND, "认领的直播商品都查询不到");
        LambdaUpdateWrapper<LiveContractCommodity> lambdaUpdateWrapper = Wrappers.lambdaUpdate(LiveContractCommodity.class)
                .in(LiveContractCommodity::getId, dto.getIdList())
                .eq(LiveContractCommodity::getClaimStatus, NumberCst.ZERO)
                .set(LiveContractCommodity::getClaimStatus, NumberCst.ONE);
        if (Objects.nonNull(incomeContract)) {
            lambdaUpdateWrapper.set(LiveContractCommodity::getIncomeContractId, incomeContract.getId())
                    .set(LiveContractCommodity::getIncomeContractCode, incomeContract.getContractCode())
                    .set(LiveContractCommodity::getCustomerId, incomeContract.getCustomerId())
                    .set(LiveContractCommodity::getCooperateBrand, incomeContract.getCooperateBrand())
                    .set(LiveContractCommodity::getLiveContractCategory, incomeContract.getLiveContractCategory())
                    .set(LiveContractCommodity::getFranchiserId, incomeContract.getOwnerId());
        } else {
            Long customerId = this.getCustomerId(dto.getCustomerName());
            lambdaUpdateWrapper
                    .set(LiveContractCommodity::getCustomerId, customerId)
                    .set(LiveContractCommodity::getCooperateBrand, dto.getCooperateBrand())
                    .set(LiveContractCommodity::getLiveContractCategory, dto.getLiveContractCategory())
                    .set(LiveContractCommodity::getFranchiserId, dto.getFranchiserId());
        }
        liveContractCommodityMapper.updateByNoStrategy(lambdaUpdateWrapper
                .set(LiveContractCommodity::getUpdateBy, UserVoContextHolder.getUserId())
                .set(LiveContractCommodity::getUpdateName, UserVoContextHolder.getUserName())
                .set(LiveContractCommodity::getUpdateDate, new Date())
        );
        Map<Long, LiveContractCommodity> dataMap = CommonUtil.defaultList(liveContractCommodityMapper.selectBatchIds(dto.getIdList())).stream().collect(Collectors.toMap(k -> k.getId(), Function.identity()));
        dataList.forEach(data -> {
            EventPublisher.post(OperateLogEvent.builder().businessId(data.getId())
                    .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                    .compare(data, dataMap.get(data.getId()))
                    .build());
        });
        return Boolean.TRUE;
    }

    @Override
    public Boolean releaseLiveContract(Long id) {
        LiveContractCommodity entity = liveContractCommodityMapper.selectById(id);
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "无此直播商品");
        liveContractCommodityMapper.updateByNoStrategy(Wrappers.lambdaUpdate(LiveContractCommodity.class)
                .eq(LiveContractCommodity::getId, id)
                .set(LiveContractCommodity::getClaimStatus, NumberCst.ZERO)
                .set(LiveContractCommodity::getIncomeContractId, null)
                .set(LiveContractCommodity::getIncomeContractCode, null)
                .set(LiveContractCommodity::getUpdateBy, UserVoContextHolder.getUserId())
                .set(LiveContractCommodity::getUpdateName, UserVoContextHolder.getUserName())
                .set(LiveContractCommodity::getUpdateDate, new Date())
        );
        EventPublisher.post(OperateLogEvent.builder().businessId(entity.getId())
                .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                .compare(entity, liveContractCommodityMapper.selectById(entity.getId()))
                .build());
        return Boolean.TRUE;
    }

    @Override
    public Boolean addLiveCommodityFromContractDetail(LiveContractAddCommodityDTO dto) {
        IncomeContract incomeContract = incomeContractMapper.selectById(dto.getLiveContractId());
        BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
        BusinessAssert.isTrue(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()), McnErrorCode.BUSINESS_ERROR, "非直播合同，不允许添加商品");
        BusinessAssert.isFalse(ApprovalStatusEnum.isInvalid(incomeContract.getApprovalStatus()), McnErrorCode.BUSINESS_ERROR, "直播合同已作废，不允许添加商品");
        List<LiveContractCommodity> dataList = liveContractCommodityMapper.selectBatchIds(dto.getLiveCommodityIdList());
        BusinessAssert.notEmpty(dataList, McnErrorCode.DATA_NOT_FOUND, "添加的直播商品都查询不到");
        List<String> claimedCommodityIds = CommonUtil.defaultList(dataList).stream()
                .filter(e -> Objects.equals(NumberCst.ONE, e.getClaimStatus())).map(LiveContractCommodity::getCommodityId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(claimedCommodityIds)) {
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "直播商品已被认领！商品ID：" + StringUtils.join(claimedCommodityIds, SeparatorCst.VERTICAL_LINE));
        }
        liveContractCommodityMapper.updateByNoStrategy(Wrappers.lambdaUpdate(LiveContractCommodity.class)
                .in(LiveContractCommodity::getId, dto.getLiveCommodityIdList())
                .eq(LiveContractCommodity::getClaimStatus, NumberCst.ZERO)
                .set(LiveContractCommodity::getClaimStatus, NumberCst.ONE)
                .set(LiveContractCommodity::getIncomeContractId, incomeContract.getId())
                .set(LiveContractCommodity::getIncomeContractCode, incomeContract.getContractCode())
                .set(LiveContractCommodity::getCustomerId, incomeContract.getCustomerId())
                .set(LiveContractCommodity::getCooperateBrand, incomeContract.getCooperateBrand())
                .set(LiveContractCommodity::getLiveContractCategory, incomeContract.getLiveContractCategory())
                .set(LiveContractCommodity::getFranchiserId, incomeContract.getOwnerId())
                .set(LiveContractCommodity::getUpdateBy, UserVoContextHolder.getUserId())
                .set(LiveContractCommodity::getUpdateName, UserVoContextHolder.getUserName())
                .set(LiveContractCommodity::getUpdateDate, new Date())
        );
        Map<Long, LiveContractCommodity> dataMap = CommonUtil.defaultList(liveContractCommodityMapper.selectBatchIds(dto.getLiveCommodityIdList())).stream().collect(Collectors.toMap(k -> k.getId(), Function.identity()));
        dataList.forEach(data -> {
            EventPublisher.post(OperateLogEvent.builder().businessId(data.getId())
                    .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                    .compare(data, dataMap.get(data.getId()))
                    .build());
        });
        return Boolean.TRUE;
    }


    @Override
    public String importCommodity(List<CommodityInputDTO> inputList, Long lsId) {
        //1、校验参数格式
        List<CommodityOutputDTO> outputList = inputList.stream().map(e -> {
            CommodityOutputDTO outputDTO = new CommodityOutputDTO();
            BeanUtils.copyProperties(e, outputDTO);
            outputDTO.setLivePrice(CommonUtil.strToBigDecimal(e.getLivePriceStr()));
            outputDTO.setClickRate(CommonUtil.strToBigDecimal(e.getClickRateStr()));
            outputDTO.setTradeTransfRate(CommonUtil.strToBigDecimal(e.getTradeTransfRateStr()));
            outputDTO.setBeforeRefundRate(CommonUtil.strToBigDecimal(e.getBeforeRefundRateStr()));
            outputDTO.setAfterRefundRate(CommonUtil.strToBigDecimal(e.getAfterRefundRateStr()));
            outputDTO.setPayGpm(CommonUtil.strToBigDecimal(e.getPayGpmStr()));
            outputDTO.setTransactedAmount(CommonUtil.strToBigDecimal(e.getTransactedAmountStr()));
            outputDTO.setBeforeRefundAmount(CommonUtil.strToBigDecimal(e.getBeforeRefundAmountStr()));
            outputDTO.setAfterRefundAmount(CommonUtil.strToBigDecimal(e.getAfterRefundAmountStr()));
            outputDTO.setFailedReason(ValidatorUtil.getJointValidateResult(outputDTO, SeparatorCst.LINE_BREAK));
            return outputDTO;
        }).collect(Collectors.toList());
        //2、校验唯一性
        List<String> repeatedVouchers = outputList.stream().filter(e -> Objects.nonNull(e.getCommodityId()))
                .collect(Collectors.groupingBy(e -> e.getCommodityId(), Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue().longValue() > 1L).map(Map.Entry::getKey).collect(Collectors.toList());
        outputList.forEach(e -> {
            if (Objects.nonNull(e.getCommodityId())) {
                if (repeatedVouchers.contains(e.getCommodityId())) {
                    e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "相同的直播时间和主播存在商品ID重复，请去重后导入！"));
                }
            }
        });

        List<CommodityOutputDTO> successList = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason())).collect(Collectors.toList());
        List<CommodityOutputDTO> failedList = outputList.stream().filter(e -> StringUtils.isNotBlank(e.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(successList)) {
            List<String> commodityIds = successList.stream().map(CommodityOutputDTO::getCommodityId).collect(Collectors.toList());
            Map<String, LiveContractCommodity> commodityMap = CommonUtil.defaultList(liveContractCommodityMapper.selectList(Wrappers.lambdaQuery(LiveContractCommodity.class)
                    .in(LiveContractCommodity::getCommodityId, commodityIds)
                    .eq(LiveContractCommodity::getLsId, lsId)
                    .eq(LiveContractCommodity::getIsDelete, NumberCst.ZERO))).stream().collect(
                    Collectors.toMap(k -> StringUtils.joinWith(SeparatorCst.PLUS, k.getCommodityId(), k.getLsId()), Function.identity(), (x, y) -> x));

            List<LiveContractCommodity> insertList = new ArrayList<>();
            List<LiveContractCommodity> updateList = new ArrayList<>();
            for (CommodityOutputDTO e : successList) {
                LiveContractCommodity liveContractCommodity = new LiveContractCommodity();
                BeanUtils.copyProperties(e, liveContractCommodity);
                try {
                    if(StringUtils.isNotBlank(e.getFirstNewDate())) {
                        Date firstNewDate = DateUtils.parseDate(e.getFirstNewDate(), McnConstant.LONG_DATE_FORMAT, McnConstant.SHORT_DATE_FORMAT,
                                McnConstant.LONG_DATE_FORMAT2, McnConstant.SHORT_DATE_FORMAT2);
                        liveContractCommodity.setFirstNewDate(firstNewDate);
                    }
                } catch (ParseException parseException) {
                    log.error("importCommodity : 商品id:" + e.getCommodityId() + ",商品名称:" + e.getCommodityName() + ";" + parseException.getMessage());
                }
                LiveContractCommodity commodity = commodityMap.get(StringUtils.joinWith(SeparatorCst.PLUS, e.getCommodityId(), lsId));
                if (Objects.nonNull(commodity)) {
                    liveContractCommodity.setId(commodity.getId());
                    liveContractCommodity.setUpdateName(UserVoContextHolder.getUserName());
                    liveContractCommodity.setUpdateBy(UserVoContextHolder.getUserId());
                    liveContractCommodity.setUpdateDate(new Date());
                    updateList.add(liveContractCommodity);
                } else {
                    liveContractCommodity.setLsId(lsId);
                    liveContractCommodity.setClaimStatus(NumberCst.ZERO);
                    liveContractCommodity.setSettlementStatus(NumberCst.THREE);
                    liveContractCommodity.setOwnerId(UserVoContextHolder.getUserId());
                    liveContractCommodity.setOwnerName(UserVoContextHolder.getUserName());
                    liveContractCommodity.setCreateBy(UserVoContextHolder.getUserId());
                    liveContractCommodity.setCreateName(UserVoContextHolder.getUserName());
                    liveContractCommodity.setCreateDate(new Date());
                    liveContractCommodity.setDepartmentId(UserVoContextHolder.getDepartmentId());
                    liveContractCommodity.setCompanyId(UserVoContextHolder.getCompanyId());
                    liveContractCommodity.setTenantId(UserVoContextHolder.getTenantId());
                    liveContractCommodity.setUpdateBy(UserVoContextHolder.getUserId());
                    liveContractCommodity.setUpdateName(UserVoContextHolder.getUserName());
                    liveContractCommodity.setUpdateDate(new Date());
                    liveContractCommodity.setIsDelete(0);
                    insertList.add(liveContractCommodity);
                }
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                liveContractCommodityMapper.insertBatch(insertList);
            }

            if (CollectionUtils.isNotEmpty(updateList)) {
                liveContractCommodityMapper.batchUpdate(updateList);
                Set<Long> commodityIdList = updateList.stream().map(x -> x.getId()).collect(Collectors.toSet());
                List<LiveContractCommodity> list = liveContractCommodityMapper.selectList(new QueryWrapper<LiveContractCommodity>().lambda().in(LiveContractCommodity::getCommodityId, commodityIdList));
                Map<Long, LiveContractCommodity> liveContractCommodityMap = list.stream().collect(Collectors.toMap(k -> k.getId(), Function.identity(), (x, y) -> x));
                for (LiveContractCommodity commodity : updateList) {
                    LiveContractCommodity liveContractCommodity = liveContractCommodityMap.get(commodity.getId());
                    EventPublisher.post(OperateLogEvent.builder().businessId(commodity.getId())
                            .businessType(LogBusinessTypeEnum.LIVE_COMMODITY)
                            .compare(commodity, liveContractCommodity)
                            .build());
                }
            }
        }
        return generateDownloadFiledId(failedList, ImportExcelEnum.LIVE_COMMODITY);
    }


    private List<BaseCustomer> createCustomer(List<String> customerNames) {
        List<String> names = customerNames.stream().distinct().collect(Collectors.toList());
        List<BaseCustomer> customers = new ArrayList<>();
        names.forEach(name -> {
            BaseCustomer baseCustomer = new BaseCustomer();
            baseCustomer.setCustomerNameC(name);
            baseCustomer.setCustomerType(NumberCst.TEN);
            baseCustomer.setCustomerStatus(NumberCst.ZERO);
            baseCustomer.setMcnCustomerType(NumberCst.TWO);
            customers.add(baseCustomer);
        });
        return baseInfoClient.addList(customers).getObj();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String importSettlmentCommodity(List<SettlementCommodityInputDTO> inputList) {
        //1、校验参数格式
        List<SettlementCommodityOutputDTO> outputList = inputList.stream().map(e -> {
            SettlementCommodityOutputDTO outputDTO = new SettlementCommodityOutputDTO();
            BeanUtils.copyProperties(e, outputDTO);
            outputDTO.setFailedReason(ValidatorUtil.getJointValidateResult(outputDTO, SeparatorCst.LINE_BREAK));
            return outputDTO;
        }).collect(Collectors.toList());
        //2、校验唯一性
        List<String> repeatedVouchers = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason()))
                .collect(Collectors.groupingBy(e -> this.getVoucher(e.getCommodityId(), e.getAnchorName(), e.getPayMonthStr()), Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue().longValue() > 1L).map(Map.Entry::getKey).collect(Collectors.toList());
        outputList.forEach(e -> {
            if (StringUtils.isBlank(e.getFailedReason()) && repeatedVouchers.contains(this.getVoucher(e.getCommodityId(), e.getAnchorName(), e.getPayMonthStr()))) {
                e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "商品ID+主播+支付月份数据重复，导入失败，请检查后重试"));
            }
        });
        //3、校验系统数据匹配校验
        List<String> anchorNameList = outputList.stream().map(SettlementCommodityInputDTO::getAnchorName).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        List<StarPlatformInfo> anchorList = CommonUtil.supplyIfNecessary(CollectionUtils.isNotEmpty(anchorNameList), () ->
                starPlatformInfoMapper.selectList(Wrappers.lambdaQuery(StarPlatformInfo.class).select(StarPlatformInfo::getId, StarPlatformInfo::getPlatNickName)
                        .in(StarPlatformInfo::getPlatNickName, anchorNameList).eq(StarPlatformInfo::getPlatformStatus, NumberCst.ZERO)
                        .eq(StarPlatformInfo::getIsDelete, NumberCst.ZERO).orderByAsc(StarPlatformInfo::getCreateDate)));
        Map<String, Long> anchorMap = CommonUtil.defaultList(anchorList).stream().collect(HashMap::new, (n, o) -> n.putIfAbsent(o.getPlatNickName(), o.getId()), Map::putAll);
        for (SettlementCommodityOutputDTO commodityOutputDTO : outputList) {
            commodityOutputDTO.verifySysDataMatch(anchorMap, SeparatorCst.LINE_BREAK);
        }
        //4、匹配场次
        List<String> commodityIds = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason())).map(SettlementCommodityOutputDTO::getCommodityId).distinct().collect(Collectors.toList());
        List<String> anchorNames = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason())).map(SettlementCommodityInputDTO::getAnchorName).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(commodityIds) && CollectionUtils.isNotEmpty(anchorNames)) {
            Map<String, LiveCommodityMatchResultVO> matchMap = CommonUtil.defaultList(liveContractCommodityMapper.matchLiveCommodity(commodityIds, anchorNames, Long.MAX_VALUE)).stream()
                    .collect(Collectors.toMap(k -> StringUtils.joinWith(SeparatorCst.PLUS, k.getCommodityId(), k.getPlatNickName()), Function.identity()));
            outputList.forEach(e -> {
                String matchVoucher = StringUtils.joinWith(SeparatorCst.PLUS, e.getCommodityId(), e.getAnchorName());
                if (!matchMap.containsKey(matchVoucher)) {
                    e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "对应主播下不存在此直播商品ID！"));
                } else {
                    e.setMatchResultVO(matchMap.get(matchVoucher));
                }
            });
        }
        List<SettlementCommodityOutputDTO> successList = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason())).collect(Collectors.toList());
        List<SettlementCommodityOutputDTO> failedList = outputList.stream().filter(e -> StringUtils.isNotBlank(e.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(successList)) {
            List<Long> lccIds = successList.stream().map(SettlementCommodityOutputDTO::getLccId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<Long, Map<String, LiveSettlementCommodity>> settlementCommodityMap = CommonUtil.defaultList(liveSettlementCommodityMapper.selectList(Wrappers.lambdaQuery(LiveSettlementCommodity.class)
                    .in(LiveSettlementCommodity::getLccId, lccIds).eq(LiveSettlementCommodity::getIsDelete, NumberCst.ZERO)))
                    .stream().collect(Collectors.groupingBy(LiveSettlementCommodity::getLccId,
                            Collectors.toMap(k -> StringUtils.joinWith(SeparatorCst.PLUS, k.getCommodityId(), k.getPayMonth()), Function.identity())));
            List<LiveSettlementCommodity> saveList = new ArrayList<>();
            for (SettlementCommodityOutputDTO e : successList) {
                LiveSettlementCommodity commodity = this.getLiveSettlementCommodity(settlementCommodityMap, e);
                if (commodity != null) {
                    commodity.setCommodityName(e.getCommodityName());
                    commodity.setCommissionRate(e.getCommissionRate());
                    commodity.setSettlementAmount(e.getSettlementAmount());
                    commodity.setSettlementCommission(e.getSettlementCommission());
                    commodity.setSettlementPrice(e.getSettlementPrice());
                    commodity.setSettlementQty(e.getSettlementQty());
                    commodity.setShopName(e.getShopName());
                    commodity.setRealAmount(e.getRealAmount());
                    commodity.setRemark(StringUtils.defaultString(e.getRemark()));
                    if (NumberCst.ZERO.equals(commodity.getSettlementStatus())) {
                        saveList.add(commodity);
                    } else {
                        e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "该月商品订单已进入结算，不允许导入！"));
                        failedList.add(e);
                    }
                } else {
                    LiveSettlementCommodity liveSettlementCommodity = new LiveSettlementCommodity();
                    BeanUtils.copyProperties(e, liveSettlementCommodity);
                    liveSettlementCommodity.setPayMonth(DateUtil.correctDate(e.getPayMonthStr(), "yyyy-MM"));
                    liveSettlementCommodity.setSettlementStatus(NumberCst.ZERO);
                    saveList.add(liveSettlementCommodity);
                }
            }
            successList.clear();
            if (CollectionUtils.isNotEmpty(saveList)) {
                Lists.partition(saveList, McnConstant.MAX_INSERT_SIZE).forEach(subList -> {
                    BaseAssemblerUtil.batchUpdateFill(subList, UserVoContextHolder.getUserVo());
                    liveSettlementCommodityMapper.saveBatch(subList);
                });
                List<Long> insertLccIds = saveList.stream().filter(e -> Objects.isNull(e.getId())).map(LiveSettlementCommodity::getLccId).distinct().collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(insertLccIds)) {
                    liveContractCommodityMapper.updateSettlementStatusWhenImport(insertLccIds);
                }
                saveList.clear();
                //无须日志
            }
        }
        return generateDownloadFiledId(failedList, ImportExcelEnum.LIVE_SETTLMENT_COMMODITY);
    }

    /**
     * 删除直播商品
     *
     * @param dto
     */
    @Override
    public void delete(LiveCommodityClaimDTO dto) {
        // if (Objects.isNull(dto.getLiveContractId())) {
        //     throw new BusinessException(McnErrorCode.PARAM_ERROR);
        // }
        List<LiveStarSettlementDetail> liveStarSettlementDetails = liveStarSettlementDetailMapper.selectList(new QueryWrapper<LiveStarSettlementDetail>().select("distinct settlement_id").lambda().in(LiveStarSettlementDetail::getLiveCommodityId, dto.getIdList()));
        if (CollectionUtils.isNotEmpty(liveStarSettlementDetails)) {
            Set<Long> settlementIds = liveStarSettlementDetails.stream().map(x -> x.getSettlementId()).collect(Collectors.toSet());
            List<LiveStarSettlement> list = liveStarSettlementMapper.selectList(new QueryWrapper<LiveStarSettlement>().lambda().in(LiveStarSettlement::getId, settlementIds)
                    .ne(LiveStarSettlement::getApprovalStatus, LiveStarSettlementStatusEnum.INVALID.getCode()));
            if (!CollectionUtils.isEmpty(list)) {
                throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), String.format("有关联的未作废直播红人结算单%s", list.stream().map(x -> x.getSettlementCode()).collect(Collectors.joining(","))));
            }
        }
        //根据直播商品ID获取对应的非结算中的结算商品数量
        List<LiveSettlementCommodity> liveSettlementCommodities = liveSettlementCommodityMapper.selectList(new QueryWrapper<LiveSettlementCommodity>().lambda().in(LiveSettlementCommodity::getLccId, dto.getIdList())
                .in(LiveSettlementCommodity::getSettlementStatus, Arrays.asList(NumberCst.ONE, NumberCst.TWO)));
        if (CollUtil.isNotEmpty(liveSettlementCommodities)) {
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), String.format("关联的结算商品[%s]为结算中或已结算状态,不能删除", liveSettlementCommodities.stream().map(LiveSettlementCommodity::getCommodityId).collect(Collectors.joining(","))));
        }
        LiveContractCommodity entity = new LiveContractCommodity();
        entity.setIsDelete(NumberCst.ONE);
        entity.setUpdateBy(UserVoContextHolder.getUserId());
        entity.setUpdateName(UserVoContextHolder.getUserName());
        entity.setUpdateDate(new Date());
        liveContractCommodityMapper.update(entity, new QueryWrapper<LiveContractCommodity>().lambda().in(LiveContractCommodity::getId, dto.getIdList()));
    }

    /**
     * 生成下载失败的文件信息ID
     *
     * @param outputList
     * @return
     */
    private <T> String generateDownloadFiledId(List<T> outputList, ImportExcelEnum importExcelEnum) {
        if (CollectionUtils.isEmpty(outputList)) {
            return null;
        }
        String fileId = importExcelEnum.getFileId();
        stringRedisTemplate.opsForValue().set(McnConstant.CACHE_PRIFIX + fileId, JSONObject.toJSONString(outputList), 30, TimeUnit.MINUTES);
        return fileId;
    }

    /**
     * 通过客户名称获取客户ID
     *
     * @param customerName
     * @return
     */
    private Long getCustomerId(String customerName) {
        List<String> customerNameList = Lists.newArrayList(customerName);
        Map<String, Long> customerNameMap = baseInfoClient.getCustomerIdByName(customerNameList).getObj();
        if (CommonUtil.containsKey(customerNameMap, customerName)) {
            return customerNameMap.get(customerName);
        }
        customerNameMap = CommonUtil.defaultList(createCustomer(customerNameList)).stream().collect(Collectors.toMap(k -> k.getCustomerNameC(), v -> v.getCustomerId()));
        BusinessAssert.isTrue(CommonUtil.containsKey(customerNameMap, customerName), McnErrorCode.BUSINESS_ERROR, "新增客户失败！客户名称：" + customerName);
        return customerNameMap.get(customerName);
    }

    /**
     * 获取唯一凭证
     *
     * @param commodityId
     * @param anchorName
     * @param dateStr
     * @return
     */
    private String getVoucher(String commodityId, String anchorName, String dateStr) {
        return StringUtils.joinWith(SeparatorCst.PLUS, commodityId, anchorName, DateUtil.correctDate(dateStr, "yyyy-MM"));
    }

    /**
     * 获取结算商品
     *
     * @param map
     * @param e
     * @return
     */
    private LiveSettlementCommodity getLiveSettlementCommodity(Map<Long, Map<String, LiveSettlementCommodity>> map, SettlementCommodityOutputDTO e) {
        Map<String, LiveSettlementCommodity> settlementCommodityMap = CommonUtil.getMapValue(map, e.getLccId());
        if (MapUtils.isEmpty(settlementCommodityMap)) {
            return null;
        }
        return settlementCommodityMap.get(StringUtils.joinWith(SeparatorCst.PLUS, e.getCommodityId(), DateUtil.correctDate(e.getPayMonthStr(), "yyyy-MM")));
    }
}
